﻿namespace Swashbuckle.AspNetCore.SwaggerGen;

public static class TypeExtensions
{
    public static bool IsOneOf(this Type type, params Type[] possibleTypes)
    {
        return possibleTypes.Any(possibleType => possibleType == type);
    }

    public static bool IsAssignableTo(this Type type, Type baseType)
    {
        return baseType.IsAssignableFrom(type);
    }

    public static bool IsAssignableToOneOf(this Type type, params Type[] possibleBaseTypes)
    {
        return possibleBaseTypes.Any(possibleBaseType => possibleBaseType.IsAssignableFrom(type));
    }

    public static bool IsConstructedFrom(this Type type, Type genericType, out Type constructedType)
    {
        constructedType = new[] { type }
            .Union(type.GetInheritanceChain())
            .Union(type.GetInterfaces())
            .FirstOrDefault(i => i.IsConstructedGenericType && i.GetGenericTypeDefinition() == genericType);

        return (constructedType != null);
    }

    public static bool IsReferenceOrNullableType(this Type type)
    {
        return !type.IsValueType || Nullable.GetUnderlyingType(type) != null;
    }

    public static object GetDefaultValue(this Type type)
    {
        return type.IsValueType
            ? Activator.CreateInstance(type)
            : null;
    }

    public static Type[] GetInheritanceChain(this Type type)
    {
        if (type.IsInterface)
        {
            return type.GetInterfaces();
        }

        var inheritanceChain = new List<Type>();

        var current = type;
        while (current.BaseType != null)
        {
            inheritanceChain.Add(current.BaseType);
            current = current.BaseType;
        }

        return [.. inheritanceChain];
    }
}
